/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package service.purchasingServices;

import com.openbrew.openbrewrf.Brews;
import com.openbrew.openbrewrf.Hops;
import com.openbrew.openbrewrf.Malt;
import com.openbrew.openbrewrf.POLines;
import com.openbrew.openbrewrf.PitchNotes;
import com.openbrew.openbrewrf.PurchaseOrder;
import com.openbrew.openbrewrf.StockCode;
import com.openbrew.openbrewrf.Supplies;
import com.openbrew.openbrewrf.Yeast;
import com.openbrew.openbrewrf.views.YeastView;
import forcastTools.RecPOTbl;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import service.enumerations.WarehouseIngredient;

/**
 *
 * @author dchapman
 */
@Stateless
@Path("com.openbrew.openbrewrf.recommendedpo")
public class RecommendedPOReportREST {
    @PersistenceContext(unitName = "com.openBrew_openBrewRF_war_1.0PU")
    private EntityManager em;
    
    public RecommendedPOReportREST() {
    }
    
    private List<Malt> maltItems = new ArrayList<Malt>();
    private List<Hops> hopItems = new ArrayList<Hops>();
    private List<Brews> brewItems = new ArrayList<Brews>();
    private List<Supplies> supplies = new ArrayList<Supplies>();
    private final List<RecPOTbl> recPOS = new ArrayList<RecPOTbl>();
    private List<PurchaseOrder> pos = new ArrayList<PurchaseOrder>();
    
    private void loadMalts(){
        maltItems.removeAll(maltItems);
        maltItems = getEntityManager().createNamedQuery("Malt.findAll", Malt.class).getResultList();
    }
    
    private void loadHops(){
        hopItems.removeAll(hopItems);
        hopItems = getEntityManager().createNamedQuery("Hops.findAll", Hops.class).getResultList();
    }
    
    private void loadBrews(){
        brewItems.removeAll(brewItems);
        brewItems = getEntityManager().createNamedQuery("Brews.findAll", Brews.class).getResultList();
    }
    
    private void loadSupplies(){
        supplies.removeAll(supplies);
        supplies = getEntityManager().createNamedQuery("Supplies.findAll", Supplies.class).getResultList();
    }
    
    private void loadPurchaseOrders(){
        pos.removeAll(pos);
        pos = getEntityManager().createNamedQuery("PurchaseOrder.findAll", PurchaseOrder.class).getResultList();
    }
    
    private Yeast getYeast(final int yeastID){
        TypedQuery<Yeast> query = getEntityManager().createQuery(
                "SELECT y FROM Yeast y WHERE y.yid = ?1"
                , Yeast.class);
        query.setParameter(1, yeastID);
        Yeast yeast = query.getSingleResult();
        return yeast;
    }
    
    @GET
    @Path("getRecPOS")
    @Produces(MediaType.APPLICATION_XML)
    public List<RecPOTbl> find() {
        recPOS.removeAll(recPOS);
        loadMalts();
        loadHops();
        loadBrews();
        loadSupplies();
        loadBrews();
        loadPurchaseOrders();
        
        //Check Malt
        for(final Malt malt : maltItems){
            //Check malt to see if it needs to be ordered.
            final double minLevel = (double)malt.getMaltMinimum();
            final double allocation = (double)malt.getMaltSpoken();
            final double onHand = (double)malt.getMaltOnHand();
            final double onOrder = (double)malt.getMaltOnOrder();
            final double amountPer = (double)malt.getMaltBagLbs();
            
            double toOrder = getAmtToOrder(minLevel, allocation, onHand, onOrder, amountPer);
            if(toOrder > 0){
                int numBags = (int)Math.ceil(toOrder/(double)malt.getMaltBagLbs());
                final StockCode sc = malt.getStockCode();
                final int unordered = getUnOrderedQty(sc);
                boolean onPO = false;
                if(unordered > 0){
                    numBags = numBags - unordered;
                    if(numBags < 0){
                        numBags = 0;
                    }
                    onPO = true;
                }
                if(!doesValueExist(sc)){
                    recPOS.add(new RecPOTbl(sc.getStockVendID().getVid(),sc.getStockID(),numBags
                          ,WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId(),onPO, null, malt
                          , null, null));
                }
            }
        }
        
        //Check hops
        for(final Hops hop : hopItems){
            //Check malt to see if it needs to be ordered.
            final double minLevel = (double)hop.getHopMinimum();
            final double allocation = (double)hop.getHopSpoken();
            final double onHand = (double)hop.getHopOnHand();
            final double onOrder = (double)hop.getHopOnOrder();
            final double amountPer = (double)hop.getHopBagLbs();
            
            double toOrder = getAmtToOrder(minLevel, allocation, onHand, onOrder, amountPer);
            if(toOrder > 0){
                int numBags = (int)Math.ceil(toOrder/(double)hop.getHopBagLbs());
                final StockCode sc = hop.getStockCode();
                final int unordered = getUnOrderedQty(sc);
                boolean onPO = false;
                if(unordered > 0){
                    numBags = numBags - unordered;
                    if(numBags < 0){
                        numBags = 0;
                    }
                    onPO = true;
                }
                if(!doesValueExist(sc)){
                    recPOS.add(new RecPOTbl(sc.getStockVendID().getVid(),sc.getStockID(),numBags
                        ,WarehouseIngredient.HOPS.getDbId(),onPO, hop, null, null, null));
                }
            }
        }
        
        //Check Yeast
        for(final Brews brew : brewItems){
            if((brew.getBState() < 20)&&(brew.getBState() > 5)){
                if(brew.getPitchNoteCollection()!=null){
                    PitchNotes pn = brew.getPitchNoteCollection().get(0);
                    YeastView yeastView = null;
                    if(pn.getYeastID()!=null){
                        yeastView = pn.getYeastID();
                    } else {
                        yeastView = pn.getYeastGenId().getYGYeastID();
                    }
                    //Yeast yeast = brew.getYeastID();
                    Yeast yeast = getYeast(yeastView.getYid());
                    if(pn.getYeastGenId()!=null){
                        if(pn.getYeastGenId().getYeastGenID() >= yeast.getMaxGen()){
                            int numBags = 1;
                            final StockCode sc = yeast.getStockCode();
                            final int unordered = getUnOrderedQty(sc);
                            boolean onPO = false;
                            if(unordered > 0){
                                numBags = numBags - unordered;
                                if(numBags < 0){
                                    numBags = 0;
                                }
                                onPO = true;
                            }
                            if(!doesValueExist(sc)){
                                recPOS.add(new RecPOTbl(sc.getStockVendID().getVid(),sc.getStockID(),numBags
                                    ,WarehouseIngredient.YEAST.getDbId(),onPO, null, null, yeast, null));
                            }
                        }
                    }
                }
            }
        }
        
        //Now check all the rest of the inventory.
        for(final Supplies supply : supplies){
            //Check malt to see if it needs to be ordered.
            final double minLevel = (double)supply.getMinimumQty();
            final double allocation = (double)supply.getSupSpoken();
            final double onHand = (double)supply.getSupOnHand();
            final double onOrder = (double)supply.getSupOnOrder();
            
            double toOrder = getAmtToOrder(minLevel, allocation, onHand, onOrder, 1);
            if(toOrder > 0){
                int numBags = (int)Math.ceil(toOrder/(double)supply.getSupQtyPer());
                final StockCode sc = supply.getStockCode();
                //final StockCode sc = getStockCode(supply.getSupplyID(), supply.getWearhouseID());
                final int unordered = getUnOrderedQty(sc);
                boolean onPO = false;
                if(unordered > 0){
                    numBags = numBags - unordered;
                    if(numBags < 0){
                        numBags = 0;
                    }
                    onPO = true;
                }
                if(!doesValueExist(sc)){
                    if(sc.getStockVendID()!=null){
                        recPOS.add(new RecPOTbl(sc.getStockVendID().getVid(),sc.getStockID(),numBags
                            ,supply.getSupWH(),onPO, null, null, null, supply));
                    }
                }
            }
        }
        
        return recPOS;
    }
    
    private boolean doesValueExist(final StockCode sc){
        boolean retVal = false;
        for(final RecPOTbl rec : recPOS){
            if(rec.getPartNumber() == sc.getStockID()){
                retVal = true;
            }
        }
        return retVal;
    }
    
    //----------------------------------------------------------------------------
    //Inventory processing code
    //----------------------------------------------------------------------------
    private double getAmtToOrder(final double minLevel, final double allocation, final double onHand
            , final double onOrder, final double amountPer){
        final double totOnOrder = onOrder * amountPer;
        double toOrder = 0;
        if(allocation > (onHand + totOnOrder)){
            toOrder = (allocation - (onHand + totOnOrder) + minLevel);
            if(toOrder < minLevel){
                toOrder = minLevel;
            }
        } else {
            if(((onHand + totOnOrder) - allocation) >= minLevel){
                return 0;
            } else {
                toOrder = minLevel;
            }
        }
        
        return toOrder;
    }
    
    private int getUnOrderedQty(final StockCode sc){
        int retVal = 0;
        for(final PurchaseOrder po : pos){
            if(po.getPOState() < 20){
                if(po.getPOLinesCollection().isEmpty()){
                    return retVal;
                }
                for(final POLines poline : po.getPOLinesCollection()){
                    if(poline.getPolpn().getStockID() == sc.getStockID()){
                        retVal += poline.getPOLQty();
                    }
                }
            }
        }
        return retVal;
    }
    
    protected EntityManager getEntityManager() {
        return em;
    }
}
